package restlet.description.convert;

import java.util.List;
import java.util.Map;
import java.util.Set;
import org.restlet.data.MediaType;
import org.restlet.resource.Resource;
import org.softmed.filehandling.CodeUtil;
import org.softmed.filehandling.FileUtil;

import restlet.runtime.RESTConfiguration;
import restlet.runtime.RESTModule;
import restlet.runtime.RESTResource;

public class DescriptionToRuntimeConverter extends
		RESTConfigurationXMLConverter {

	RESTConfigurationXMLConverter converter = new RESTConfigurationXMLConverter();
	FileUtil util = new FileUtil();

	public RESTConfiguration getConfiguration(String path) throws Throwable {
		RESTConfigurationDescription description = getConfigurationDescription(path);
		RESTConfiguration config = convertConfiguration(description);
		return config;
	}

	public RESTConfigurationDescription getConfigurationDescription(String path)
			throws Throwable {
		String xml = util.readFromFile(path);
		RESTConfigurationDescription description = (RESTConfigurationDescription) converter
				.fromXML(xml);
		return description;
	}

	public RESTConfiguration convertConfiguration(
			RESTConfigurationDescription description) throws Throwable {
		RESTConfiguration config = new RESTConfiguration();
		List<String> moduleFiles = description.getModuleConfigurationFiles();
		for (String moduleDescriptionFile : moduleFiles) {
			String xml = util.readFromFile(moduleDescriptionFile);
			RESTModuleDescription moduleDescription = (RESTModuleDescription) converter
					.fromXML(xml);
			config.addModule(convertModule(moduleDescription));
		}

		return config;
	}

	public RESTModule convertModule(RESTModuleDescription description)
			throws Throwable {
		RESTModule module = new RESTModule();
		module.setName(description.getName());
		List<RESTResourceDescription> resources = description.getResources();

		for (RESTResourceDescription resourceDescription : resources) {
			module.addResource(convertResource(resourceDescription));
		}

		return module;
	}

	public RESTResource convertResource(RESTResourceDescription description)
			throws Throwable {
		RESTResource resource = new RESTResource();
		resource.setURI(description.getUri());

		if (description.getHandler() != null) {
			Class<?> type = util.getClass(description.getHandler());
			resource.setHandler((Resource) type.newInstance());

			return resource;
		}

		// GET handlers setup
		Map<MediaType, GetHandler> handlers = resource.getGetHandlers();
		Map<String, String> handlersDescription = description.getGetHandlers();

		Set<String> keyDescriptions = handlersDescription.keySet();
		MediaType mediaType = null;
		Class<?> type = null;
		for (String mediaTypeName : keyDescriptions) {
			mediaType = MediaType.valueOf(mediaTypeName);
			type = util.getClass(handlersDescription.get(mediaTypeName));
			handlers.put(mediaType, (GetHandler) type.newInstance());
		}

		// POST handlers setup
		Map<MediaType, PostHandler> postHandlers = resource.getPostHandlers();
		handlersDescription = description.getPostHandlers();

		keyDescriptions = handlersDescription.keySet();
		mediaType = null;
		type = null;
		for (String mediaTypeName : keyDescriptions) {
			type = util.getClass(handlersDescription.get(mediaTypeName));
			postHandlers.put(mediaType, (PostHandler) type.newInstance());
		}

		// PUT handlers setup
		Map<MediaType, PutHandler> putHandlers = resource.getPutHandlers();
		handlersDescription = description.getPutHandlers();

		keyDescriptions = handlersDescription.keySet();
		mediaType = null;
		type = null;
		for (String mediaTypeName : keyDescriptions) {
			type = util.getClass(handlersDescription.get(mediaTypeName));
			putHandlers.put(mediaType, (PutHandler) type.newInstance());
		}

		if (description.getDeleteHandler() != null) {
			type = util.getClass(description.getDeleteHandler());
			resource.setDeleteHandler((DeleteHandler) type.newInstance());
		}

		return resource;

	}

	public RESTConfigurationXMLConverter getConverter() {
		return converter;
	}

}
